﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.DirectoryServices;
using System.Security.Principal;
using AppEszköz.Config;

namespace AppEszköz.Security
{
    public class ActiveDirectorySearcher
    {
        private string LDAPUser = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "LDAPUser");
        private string LDAPPassword = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "LDAPPassword");
        private string BranchLDAPI = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "BranchURL");
        private string FmerLDAPI = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "FmerURL");
        private string CBCLDAPI = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "CBCURL");
        private string CBCLDAPUser = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "CBCLDAPUser");
        private string CBCLDAPPassword = ConfigRegistryHelper.GetConfig("LDAP", "LDAP", "CBCLDAPPassword");

        [Description("Given Name of the User")]
        public string FirstName { get; private set; }

        public string LastName { get; private set; }

        public string Phone { get; private set; }

        public string EMail { get; private set; }

        public string Department { get; private set; }

        public string ADRegion { get; private set; }

        public ArrayList MembershipList(string GroupName)
        {
            return this.MembershipList(GroupName, true);
        }

        public ArrayList MembershipList(string GroupName, bool IsFMER)
        {
            ArrayList arrayList = new ArrayList();
            string path = IsFMER ? this.FmerLDAPI : this.CBCLDAPI;
            string username = IsFMER ? this.LDAPUser : this.CBCLDAPUser;
            string password = IsFMER ? this.LDAPPassword : this.CBCLDAPPassword;
            string str = IsFMER ? "cn" : "objectSid";
            DirectorySearcher directorySearcher1 = new DirectorySearcher(new DirectoryEntry(path, username, password, AuthenticationTypes.Secure));
            directorySearcher1.Filter = $"{(object) str}={(object) GroupName}";
            directorySearcher1.PropertiesToLoad.Clear();
            foreach (SearchResult searchResult in directorySearcher1.FindAll())
            {
                DirectoryEntry directoryEntry1 = searchResult.GetDirectoryEntry();
                directoryEntry1.RefreshCache();
                for (int index = 0; index < directoryEntry1.Properties["member"].Count; ++index)
                {
                    DirectoryEntry directoryEntry2 = new DirectoryEntry(path + (object)"/" + (string)directoryEntry1.Properties["member"][index], username, password, AuthenticationTypes.Secure);
                    if (directoryEntry2.SchemaClassName == "foreignSecurityPrincipal" || directoryEntry2.SchemaClassName == "group")
                    {
                        string GroupName1 = directoryEntry2.Name;
                        if (GroupName1.Length > 3)
                            GroupName1 = GroupName1.Substring(3);
                        arrayList.AddRange((ICollection)this.MembershipList(GroupName1, directoryEntry2.SchemaClassName == "group"));
                    }
                    else if (directoryEntry2.Properties["sAMAccountName"].Count > 0)
                        arrayList.Add(directoryEntry2.Properties["sAMAccountName"][0]);
                }
            }
            if (IsFMER)
            {
                DirectorySearcher directorySearcher2 = new DirectorySearcher(new DirectoryEntry(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure));
                directorySearcher2.Filter = $"cn={(object) GroupName}";
                directorySearcher2.PropertiesToLoad.Clear();
                foreach (SearchResult searchResult in directorySearcher2.FindAll())
                {
                    DirectoryEntry directoryEntry1 = searchResult.GetDirectoryEntry();
                    directoryEntry1.RefreshCache();
                    for (int index = 0; index < directoryEntry1.Properties["member"].Count; ++index)
                    {
                        DirectoryEntry directoryEntry2 = new DirectoryEntry(this.BranchLDAPI + (object)"/" + (string)directoryEntry1.Properties["member"][index], this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure);
                        if (directoryEntry2.Properties["sAMAccountName"].Count > 0)
                            arrayList.Add(directoryEntry2.Properties["sAMAccountName"][0]);
                    }
                }
            }
            return arrayList;
        }

        public ArrayList GroupList(string UserName)
        {
            ArrayList arrayList = new ArrayList();
            foreach (SearchResult searchResult in new DirectorySearcher(new DirectoryEntry(this.FmerLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure))
            {
                Filter = $"sAMAccountName={(object) UserName}"
            }.FindAll())
            {
                foreach (object obj in (CollectionBase)searchResult.GetDirectoryEntry().Properties["memberOf"])
                    arrayList.Add((object)(string)obj);
            }
            foreach (SearchResult searchResult in new DirectorySearcher(new DirectoryEntry(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure))
            {
                Filter = $"sAMAccountName={(object) UserName}"
            }.FindAll())
            {
                foreach (object obj in (CollectionBase)searchResult.GetDirectoryEntry().Properties["memberOf"])
                    arrayList.Add((object)(string)obj);
            }
            return arrayList;
        }

        public bool UserInGroup(string UserName, string GroupName)
        {
            return this.UserInGroup(UserName, (string)null, GroupName);
        }

        public bool UserInGroup(string UserName, string Password, string GroupName)
        {
            return this.UserInGroup(UserName, Password, GroupName, (string)null);
        }

        public bool UserInGroup(string UserName, string Password, string GroupName, string Domain)
        {
            return this.UserInGroup(UserName, Password, GroupName, Domain, true);
        }

        private bool UserInGroup(string UserName, string Password, string GroupName, string domain, bool followControlGroups)
        {
            this.WriteToLog("Asked whether user " + UserName + " is in " + GroupName);
            if (UserName.Contains("\\"))
            {
                string[] strArray = UserName.Split('\\');
                domain = strArray[0].ToLower();
                UserName = strArray[1];
            }
            if (GroupName.ToUpper().EndsWith("CONTROL"))
            {
                if (followControlGroups)
                    return this.UserInControlGroup(UserName, GroupName, domain);
            }
            try
            {
                if ((string.IsNullOrEmpty(domain) || domain == "fmer") && this.UserInFMERGroup(UserName, Password, GroupName))
                {
                    this.WriteToLog("User " + UserName + " is in " + GroupName + " in the FMER domain");
                    return true;
                }
                if ((string.IsNullOrEmpty(domain) || domain == "branch") && this.UserInBRANCHGroup(UserName, Password, GroupName))
                {
                    this.WriteToLog("User " + UserName + " is in " + GroupName + " in the BRANCH domain");
                    return true;
                }
                if ((string.IsNullOrEmpty(domain) || domain == "cbcinternal") && this.UserInCBCGroup(UserName, Password, GroupName))
                {
                    this.WriteToLog("User " + UserName + " is in " + GroupName + " in the CBCInternal domain");
                    return true;
                }
                this.WriteToLog("User " + UserName + " is NOT in " + GroupName + " in the " + domain + " domain");
            }
            catch (Exception ex)
            {
                this.WriteToLog("DirectorySearcher has an exception when searching group membership:" + ex.ToString());
            }
            return false;
        }

        public bool UserInFMERGroup(string UserName, string Password, string GroupName)
        {
            using (DirectorySearcher directorySearcher = new DirectorySearcher(!string.IsNullOrEmpty(Password) ? new DirectoryEntry(this.FmerLDAPI, "fmer\\" + UserName, Password) : new DirectoryEntry(this.FmerLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure)))
            {
                directorySearcher.Filter = $"sAMAccountName={(object) UserName}";
                foreach (SearchResult searchResult in directorySearcher.FindAll())
                {
                    foreach (string str in (CollectionBase)searchResult.GetDirectoryEntry().Properties["memberOf"])
                    {
                        if (str.ToLower().IndexOf("cn=" + GroupName.ToLower() + ",", StringComparison.Ordinal) >= 0)
                            return true;
                    }
                }
            }
            return false;
        }

        public bool UserInBRANCHGroup(string UserName, string Password, string GroupName)
        {
            using (DirectorySearcher directorySearcher = new DirectorySearcher(!string.IsNullOrEmpty(Password) ? new DirectoryEntry(this.BranchLDAPI, "branch\\" + UserName, Password) : new DirectoryEntry(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure)))
            {
                directorySearcher.Filter = $"sAMAccountName={(object) UserName}";
                foreach (SearchResult searchResult in directorySearcher.FindAll())
                {
                    foreach (string str in (CollectionBase)searchResult.GetDirectoryEntry().Properties["memberOf"])
                    {
                        if (str.ToLower().IndexOf("cn=" + GroupName.ToLower() + ",", StringComparison.Ordinal) >= 0)
                            return true;
                    }
                }
            }
            return false;
        }

        public bool UserInCBCGroup(string UserName, string Password, string GroupName)
        {
            using (DirectorySearcher directorySearcher = new DirectorySearcher(!string.IsNullOrEmpty(Password) ? new DirectoryEntry(this.CBCLDAPI, "cbcinternal\\" + UserName, Password) : new DirectoryEntry(this.CBCLDAPI, this.CBCLDAPUser, this.CBCLDAPPassword, AuthenticationTypes.Secure)))
            {
                directorySearcher.Filter = $"sAMAccountName={(object) UserName}";
                foreach (SearchResult searchResult in directorySearcher.FindAll())
                {
                    foreach (string str in (CollectionBase)searchResult.GetDirectoryEntry().Properties["memberOf"])
                    {
                        if (str.ToLower().IndexOf("cn=" + GroupName.ToLower() + ",", StringComparison.Ordinal) >= 0)
                            return true;
                    }
                }
            }
            return false;
        }

        public bool UserInGroupRecursive(string UserName, string GroupName)
        {
            string Domain = string.Empty;
            if (UserName.Contains("\\"))
            {
                string[] strArray = UserName.Split('\\');
                Domain = strArray[0];
                UserName = strArray[1];
            }
            if (GroupName.ToUpper().EndsWith("CONTROL"))
                return this.UserInControlGroup(UserName, GroupName, Domain);
            if (string.IsNullOrEmpty(Domain))
            {
                if (this.UserInGroupRecursive(UserName, GroupName, "FMER") || this.UserInGroupRecursive(UserName, GroupName, "Branch") || this.UserInGroupRecursive(UserName, GroupName, "CBCInternal"))
                    return true;
            }
            else if (this.UserInGroupRecursive(UserName, GroupName, Domain))
                return true;
            return false;
        }

        private bool UserInControlGroup(string UserName, string GroupName, string Domain)
        {
            SearchResult one = new DirectorySearcher()
            {
                SearchRoot = new DirectoryEntry()
                {
                    Path = this.FmerLDAPI,
                    Username = this.LDAPUser,
                    Password = this.LDAPPassword,
                    AuthenticationType = AuthenticationTypes.Secure
                },
                Filter = ("(cn=" + GroupName + ")"),
                PropertiesToLoad = {
          "member"
        }
            }.FindOne();
            if (one != null)
            {
                List<string> list = new List<string>();
                foreach (object obj in (ReadOnlyCollectionBase)one.Properties["member"])
                {
                    string ForeignSecurityPrincipal = obj.ToString();
                    string str = ForeignSecurityPrincipal.ToLower() + ",";
                    if (str.Contains("cn=" + UserName.ToLower() + ","))
                    {
                        this.WriteToLog("User " + UserName + " is direct member of " + GroupName);
                        return true;
                    }
                    if (str.Contains("cn=foreignsecurityprincipals") || str.Contains("ou=user groups") || str.Contains("ou=security groups"))
                        list.Add(this.GetUserNameOfFSP(ForeignSecurityPrincipal));
                }
                list.Sort();
                list.Reverse();
                if (list.Count == 3)
                {
                    string str = list[1];
                    list.Remove(str);
                    list.Add(str);
                }
                foreach (string str in list)
                {
                    char[] chArray = new char[1]
                    {
            '\\'
                    };
                    string[] strArray = str.Split(chArray);
                    if (strArray.Length > 1 && (string.IsNullOrEmpty(Domain) || Domain.Equals(strArray[0], StringComparison.CurrentCultureIgnoreCase)) && this.UserInGroup(UserName, "", strArray[1], Domain, false))
                        return true;
                }
            }
            else
                this.WriteToLog("Control group of " + GroupName + " not found");
            return false;
        }

        private bool UserInGroupRecursive(string UserName, string GroupName, string Domain)
        {
            this.WriteToLog("Asked whether user " + UserName + " is in " + GroupName + " for " + Domain);
            DirectoryEntry directoryEntry1 = new DirectoryEntry();
            directoryEntry1.Path = "LDAP://" + Domain;
            directoryEntry1.AuthenticationType = AuthenticationTypes.Secure;
            SearchResult one1 = new DirectorySearcher()
            {
                SearchRoot = directoryEntry1,
                Filter = ("(samAccountName=" + UserName + ")"),
                ReferralChasing = ReferralChasingOption.All,
                PropertiesToLoad = {
          "displayName"
        }
            }.FindOne();
            if (one1 != null)
            {
                DirectoryEntry directoryEntry2 = one1.GetDirectoryEntry();
                directoryEntry2.RefreshCache(new string[1]
                {
          "tokenGroups"
                });
                foreach (byte[] binaryForm in (CollectionBase)directoryEntry2.Properties["tokenGroups"])
                {
                    SecurityIdentifier securityIdentifier = new SecurityIdentifier(binaryForm, 0);
                    SearchResult one2 = new DirectorySearcher()
                    {
                        SearchRoot = directoryEntry1,
                        Filter = ("(objectSid=" + securityIdentifier.Value + ")"),
                        PropertiesToLoad = {
              "distinguishedName"
            }
                    }.FindOne();
                    if (one2 != null && ((string)one2.Properties["distinguishedName"][0] + (object)",").Contains("CN=" + GroupName + ","))
                    {
                        this.WriteToLog("User " + UserName + " is in " + GroupName + " in the " + Domain + " domain");
                        return true;
                    }
                }
            }
            else
                this.WriteToLog("User " + UserName + " not found in the " + Domain + " domain");
            this.WriteToLog("User " + UserName + " not found in the " + Domain + " domain");
            return false;
        }

        private string GetUserNameOfFSP(string ForeignSecurityPrincipal)
        {
            return ((NTAccount)new SecurityIdentifier((byte[])new DirectoryEntry("LDAP://" + ForeignSecurityPrincipal).InvokeGet("objectSid"), 0).Translate(typeof(NTAccount))).ToString();
        }

        public void GetUserAttributes(string UserName)
        {
            UserName = UserName.ToUpper();
            string str = string.Empty;
            string[] strArray = UserName.Split('\\');
            if (strArray != null)
            {
                if (strArray.Length > 1)
                {
                    str = strArray[0].Trim();
                    UserName = strArray[1].Trim();
                }
            }
            try
            {
                SearchResult searchResult = (SearchResult)null;
                if (str.Length > 0)
                {
                    if (str == "FMER")
                        searchResult = this.GetUserAttributesHelper(this.FmerLDAPI, this.LDAPUser, this.LDAPPassword, "FMER", UserName);
                    else if (str == "CBCINTERNAL")
                        searchResult = this.GetUserAttributesHelper(this.CBCLDAPI, this.CBCLDAPUser, this.CBCLDAPPassword, "CBCINTERNAL", UserName);
                    else if (str == "BRANCH")
                        searchResult = this.GetUserAttributesHelper(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, "BRANCH", UserName);
                }
                if (str.Length == 0 || searchResult == null)
                    searchResult = this.GetUserAttributesHelper(this.FmerLDAPI, this.LDAPUser, this.LDAPPassword, "FMER", UserName) ?? this.GetUserAttributesHelper(this.CBCLDAPI, this.CBCLDAPUser, this.CBCLDAPPassword, "CBCINTERNAL", UserName) ?? this.GetUserAttributesHelper(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, "BRANCH", UserName);
                if (searchResult != null)
                {
                    searchResult.GetDirectoryEntry();
                    try
                    {
                        this.FirstName = searchResult.Properties["givenName"][0].ToString();
                    }
                    catch
                    {
                        this.FirstName = "";
                    }
                    try
                    {
                        this.LastName = searchResult.Properties["sn"][0].ToString();
                    }
                    catch
                    {
                        this.LastName = "";
                    }
                    try
                    {
                        this.EMail = searchResult.Properties["mail"][0].ToString();
                    }
                    catch
                    {
                        this.EMail = "";
                    }
                    try
                    {
                        this.Phone = searchResult.Properties["telephoneNumber"][0].ToString();
                    }
                    catch
                    {
                        this.Phone = "";
                    }
                    try
                    {
                        this.Department = searchResult.Properties["department"][0].ToString();
                        return;
                    }
                    catch
                    {
                        this.Department = "";
                        return;
                    }
                }
            }
            catch
            {
                this.FirstName = this.LastName = this.EMail = this.Phone = this.ADRegion = "";
            }
            this.FirstName = this.LastName = this.EMail = this.Phone = this.ADRegion = "";
        }

        private SearchResult GetUserAttributesHelper(string ldapi, string user, string password, string domain, string usernameToLookup)
        {
            DirectorySearcher directorySearcher = new DirectorySearcher(new DirectoryEntry(ldapi, user, password, AuthenticationTypes.Secure));
            directorySearcher.SearchScope = SearchScope.Subtree;
            directorySearcher.Filter = $"sAMAccountName={(object) usernameToLookup}";
            directorySearcher.PropertiesToLoad.Clear();
            directorySearcher.PropertiesToLoad.Add("givenName");
            directorySearcher.PropertiesToLoad.Add("sn");
            directorySearcher.PropertiesToLoad.Add("mail");
            directorySearcher.PropertiesToLoad.Add("telephoneNumber");
            directorySearcher.PropertiesToLoad.Add("department");
            this.ADRegion = domain.ToUpper();
            SearchResult searchResult = (SearchResult)null;
            if (directorySearcher != null)
                searchResult = directorySearcher.FindOne();
            return searchResult;
        }

        private void WriteToLog(string Message)
        {
            try
            {
                EventLog.WriteEntry("DirectorySearcher", Message);
            }
            catch
            {
            }
        }

        public string ClassicMembershipList(string GroupName)
        {
            ArrayList arrayList = new ArrayList();
            string str = "";
            DirectorySearcher directorySearcher1 = new DirectorySearcher(new DirectoryEntry(this.FmerLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure));
            directorySearcher1.Filter = $"cn={(object) GroupName}";
            directorySearcher1.PropertiesToLoad.Clear();
            directorySearcher1.PropertiesToLoad.Add("telephoneNumber");
            foreach (SearchResult searchResult in directorySearcher1.FindAll())
            {
                DirectoryEntry directoryEntry1 = searchResult.GetDirectoryEntry();
                directoryEntry1.RefreshCache();
                for (int index = 0; index < directoryEntry1.Properties["member"].Count; ++index)
                {
                    DirectoryEntry directoryEntry2 = new DirectoryEntry(this.FmerLDAPI + (object)"/" + (string)directoryEntry1.Properties["member"][index], this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure);
                    arrayList.Add(directoryEntry2.Properties["sAMAccountName"][0]);
                    str = str + directoryEntry2.Properties["sAMAccountName"][0] + ",";
                }
            }
            DirectorySearcher directorySearcher2 = new DirectorySearcher(new DirectoryEntry(this.BranchLDAPI, this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure));
            directorySearcher2.Filter = $"cn={(object) GroupName}";
            directorySearcher2.PropertiesToLoad.Clear();
            directorySearcher2.PropertiesToLoad.Add("telephoneNumber");
            foreach (SearchResult searchResult in directorySearcher2.FindAll())
            {
                DirectoryEntry directoryEntry1 = searchResult.GetDirectoryEntry();
                directoryEntry1.RefreshCache();
                for (int index = 0; index < directoryEntry1.Properties["member"].Count; ++index)
                {
                    DirectoryEntry directoryEntry2 = new DirectoryEntry(this.BranchLDAPI + (object)"/" + (string)directoryEntry1.Properties["member"][index], this.LDAPUser, this.LDAPPassword, AuthenticationTypes.Secure);
                    arrayList.Add(directoryEntry2.Properties["sAMAccountName"][0]);
                    str = str + directoryEntry2.Properties["sAMAccountName"][0] + ",";
                }
            }
            string[] strArray = (string[])arrayList.ToArray(typeof(string));
            return str;
        }
    }
}